package com.zzl.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName ProctectFilter
 * @Description  保护Filter（保护网站攻击）
 * 
 * @Date 2022/7/6
 * @Version 1.0
 */
@Component
@Slf4j
@WebFilter(urlPatterns = {"/**"})
public class ProctectFilter implements Filter {
    /**Jedis连接池*/
    @Autowired
    private JedisPool jedisPool;
    /**设置过期时间*/
    private static long PROCTECT_TIMEOUT_SECONDS=5;
    /**设置锁定时间*/
    private static long PROCTECT_LOCK_SECONDS=10;
    /**全局锁定KEY*/
    private static String PROCTECT_LOCK_KEY="proctect:lock:";
    /**访问网站IP 计数KEY*/
    private static String PROCTECT_NUM="proctect:num:";

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        /**
         * 网站防保护业务逻辑
         */
       Map<String,Object> map= this.proctectWeb(servletRequest,servletResponse);
        if((boolean)map.get("flag")){
          String message= (String) map.get("message");
          this.responseBodyWriter(servletRequest,servletResponse,message);
            return;
        }


        //继续执行目标方法
        filterChain.doFilter(servletRequest,servletResponse);
    }


    /**
     * 网站防保护业务逻辑
     * Map(是否执行目标方法，返回的消息提示）
     */
    public Map proctectWeb(ServletRequest servletRequest, ServletResponse servletResponse){

        Map map=new HashMap();

        //每次请求计数key 根据IP地址生成  proctect:num:ip
        String ip=servletRequest.getRemoteAddr();
        String key=PROCTECT_NUM+ip;
        //全局锁定KEY
        String keyLock=PROCTECT_LOCK_KEY+ip;

        Jedis jedis=jedisPool.getResource();

        /**
         * 判断锁定的KEY是否存在，如果存在，直接返回即可。
         */
        if(jedis.exists(keyLock)){
            //获得指定KEY 生存时间
            long timeout= jedis.ttl(keyLock);
            String message="因恶意访问，系统已限制"+timeout;

            map.put("flag",true);
            map.put("message",message);
            jedis.close();
            return map;
        }
        long count=jedis.incr(key);
        //判断是否是首次访问，要给其设计过期时间（10秒）
        if(count==1){
            jedis.expire(key,PROCTECT_TIMEOUT_SECONDS);
        }

        if(count>2){
            //锁定KEY 并限制用户访问 并设置过期时间 30秒
            jedis.setex(keyLock,PROCTECT_LOCK_SECONDS,ip);
            jedis.set(keyLock,ip);
            jedis.expire(keyLock,PROCTECT_LOCK_SECONDS);
            //获得指定KEY 生存时间
            long timeout= jedis.ttl(keyLock);
            String message="因恶意访问，系统已限制"+timeout;

            map.put("flag",true);
            map.put("message",message);
            jedis.close();
            return map;
        }
        jedis.close();

        map.put("flag",false);
        map.put("message","目标方法结果");

        return map;
    }


    /**
     * 响应数据（返回AJAX)
     */
    public void responseBodyWriter(ServletRequest request, ServletResponse response,String message){

         response.setCharacterEncoding("UTF-8");
         response.setContentType("application/json;charset=UTF-8");
        try {
            PrintWriter writer=response.getWriter();
            writer.write(message);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }




}
